package com.ty.web.monitor;

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;

import java.io.File;
import java.io.FileFilter;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 文件自动清理监视器
 * <p>
 *     当目录中的文件量超过阈值时，批量清理文件
 * </p>
 *
 * @Author Tommy
 * @Date 2024/4/22
 */
@Slf4j
public class FileAutoClearMonitor {

    // 文件监视器对象
    private FileAlterationMonitor monitor;

    // 监视目录对象
    private File dir;

    // 检测频率，单位：秒
    private Integer interval = 5;

    // 文件数量阈值
    private final Integer threshold;

    // 批量删除百分比
    private final Float percent;

    /**
     * 实例化
     */
    public FileAutoClearMonitor(File dir, Integer threshold, Float percent) {
        this.dir = dir;
        this.threshold = threshold;
        this.percent = percent;
        this.monitor = new FileAlterationMonitor(interval * 1000);
    }

    /**
     * 初始化
     *
     * @return FileAmountClearMonitor
     */
    public FileAutoClearMonitor init() {
        FileAutoClearMonitor _this = this;

        // 创建图片变化目录的文件观察者
        FileAlterationObserver observer = new FileAlterationObserver(this.dir, FileFilterUtils.or( // 监听目录及子目录中的JPG文件
                FileFilterUtils.directoryFileFilter(),
                new SuffixFileFilter(".jpg")
        ));

        // 向观察者添加事件回调对象
        observer.addListener(new FileAlterationListenerAdaptor() {
            final ConcurrentHashMap<String, Long> lastProcessRecords = new ConcurrentHashMap<>();

            @Override
            public void onFileCreate(File file) {
                String cameraSN = file.getParentFile().getName();
                long lastMs = lastProcessRecords.computeIfAbsent(cameraSN, key -> 0L);
                if (System.currentTimeMillis() - lastMs > monitor.getInterval() * percent) {
                    lastProcessRecords.put(cameraSN, System.currentTimeMillis());
                    _this.clearFiles(file.getParentFile());
                }
            }
        });

        // 向文件监视器添加观察者
        this.monitor.addObserver(observer);
        return this;
    }

    /**
     * 启动监视器
     *
     * @throws Exception
     */
    public void start() throws Exception {
        this.monitor.start();
        log.info("启动监视器【文件自动清理】：{}\t阈值：{}\tClear比例：{}%", this.dir.getPath(), this.threshold, this.percent * 100);
    }

    /**
     * 清理文件
     */
    void clearFiles(File dir) {
        if (!"Changed".equalsIgnoreCase(dir.getName())) {
            File[] files = dir.listFiles((FileFilter) new SuffixFileFilter("jpg"));
            if (files.length > threshold) {
                int exceedCount = files.length - threshold;
                int delCount = (int) (exceedCount + this.threshold * this.percent);
                log.info("清理目录：{} 文件数量：{} 超过阈值：{} 删除文件数：{}", dir.getPath(), files.length, this.threshold, delCount);

                // 清理文件
                List<File> fileList = Lists.newArrayList(files);
                fileList.stream().sorted(Comparator.comparing(File::lastModified)).limit(delCount).forEach(FileUtils::deleteQuietly);
            }
        }
    }
}
